package com.iteaj.iot.client;

import com.iteaj.iot.client.component.UdpClientComponent;
import com.iteaj.iot.client.protocol.ClientSocketProtocol;
import com.iteaj.iot.client.codec.DatagramPacketToMessageDecoder;
import com.iteaj.iot.ProtocolException;
import com.iteaj.iot.config.ConnectProperties;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.function.Consumer;

public abstract class UdpSocketClient extends SocketClient {

    public UdpSocketClient(UdpClientComponent clientComponent, ClientConnectProperties config) {
        super(clientComponent, config);
    }

    @Override
    protected void doInitOptions(Bootstrap bootstrap) {
        bootstrap.option(ChannelOption.SO_BROADCAST, true);
    }

    @Override
    protected Class<? extends Channel> channel() {
        return NioDatagramChannel.class;
    }

    @Override
    public void doConnect(Consumer<Boolean> consumer, long timeout) {
        getBootstrap().bind(0).addListener(future -> {
            connectLogger((ChannelFuture) future);
            consumer.accept(future.isSuccess());
        });
    }

    @Override
    public void doConnect(long timeout) throws ProtocolException {
        /*doing nothing*/
    }

    @Override
    protected abstract DatagramPacketToMessageDecoder createProtocolDecoder();

    /**
     * 写出的报文必须是 UdpRequestProtocol 协议类型
     * @param clientProtocol
     * @return
     */
    @Override
    public ChannelFuture writeAndFlush(ClientSocketProtocol clientProtocol) {
        // 写入Udp报文 DatagramPacket
        ClientMessage message = clientProtocol.requestMessage();
        if(message.getMessage() == null) {
            message.build();
        }

        DatagramPacket packet;
        ConnectProperties clientKey = clientProtocol.getClientKey();
        final ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getMessage());
        if(clientKey != null) {
            packet = new DatagramPacket(byteBuf, new InetSocketAddress(clientKey.getHost(), clientKey.getPort()));
        } else {
            packet = new DatagramPacket(byteBuf, new InetSocketAddress(getHost(), getPort()));
        }

        clientProtocol.setPacket(packet);

        return super.writeAndFlush(clientProtocol);
    }
}
